/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_variable.cpp                                                       *
 ****************************************************************************/

#include "elisa_variable.h"
#include <iostream>

USING_ELISA

// initialization of static variables
int Variable::count = 0;


MapCmp VariableImplCmpChooser::m_cmpMap;


VariableImpl *SplitNode::getVariableImplementation()
{
	return m_tree->getVariable(m_indexDomain);
}

/*
const long ChangeHeap::DefaultHeapSize	= 262144 * 100; // (256kBytes)
const long ChangeHeap::DefaultMaxBox	= 65536 * 10;	// (2^16 boxes)
*/
const long ChangeHeap::DefaultHeapSize	= 262144 * 32 * 100;
const long ChangeHeap::DefaultMaxBox	= 65536 * 32 * 10;

//--------------------------------------------------------------------------
// class SearchTree
//--------------------------------------------------------------------------


SearchTree::SearchTree (Heap *heap, ChangeHeap *changeHeap)
: m_heap(std::auto_ptr<Heap>(heap)), 
  m_changeHeap(std::auto_ptr<ChangeHeap>(changeHeap)),
  m_dfs(true)
{
	if (m_heap.get() == 0) m_heap = std::auto_ptr<Heap>(new HeapStack);
	if (m_changeHeap.get() == 0) m_changeHeap = std::auto_ptr<ChangeHeap>(new ChangeHeap());
	m_root = m_current = new SplitNode(this);
}

SearchTree::~SearchTree ()
{
	//delete m_heap;
	//delete m_changeHeap;
	delete m_root;
}

bool SearchTree::isEmpty() const
{
	if (m_dfs) {
		return(m_root->isExplored());
	} else {
		return m_heap->isEmpty();
	}
}

bool SearchTree::isSplittable() const
{
	VarImplMap::const_iterator it;
	for (it = m_varMap.begin(); it != m_varMap.end(); ++it) {
		if ((*it).second->isSplittable()) {
			return true;
		}
	}
	return false;
}

Box *SearchTree::toPoint() const
{
	Box *b = m_heap->copyBox(); // copy of the current box
	VarImplMap::const_iterator it;
	for (it = m_varMap.begin(); it != m_varMap.end(); ++it) {
		(*it).second->toPoint(b);
	}
	return b;
}

void SearchTree::add(VariableImpl *v)
{
	m_varMap[v->getIndexDomain()] = v;
}

VariableImpl *SearchTree::getVariable(long indexDomain)
{
	return m_varMap[indexDomain];
}


//--------------------------------------------------------------------------
// class Variable
//--------------------------------------------------------------------------

Variable::Variable(Domain *domain, const std::string & name)
: m_implementation(),
  m_domain(domain),
  m_name(name)
{
	if (m_name.compare("") == 0) {
		char n[11];
		createAnonymousName(n, count);
		m_name = n;
	}

	++count;
}

Variable::~Variable()
{
	/*
	if (m_implementation != NULL) {
		delete m_implementation;
	}
	*/

	if (m_domain != NULL) {
		delete m_domain;
	}

	--count;
}

void Variable::createAnonymousName(char *c, int n)
{
	int i = 0;
	char ci[10];

	/// create the inverse of n (e.g. 102 -> 201) in ci
	if (n == 0) {
		ci[i] = '0';
		ci[i + 1] = '\0';
	} else {
		while (n > 0) {
			ci[i++] = '0' + (n % 10);
			n /= 10;
		}
		ci[i] = '\0';
	}

	/// create the variable name in c
	c[0] = 'v';
	int j = 1;
	for (int k = strlen(ci) - 1; k >= 0; --k, ++j) c[j] = ci[k];
	c[j] = '\0';
}

//--------------------------------------------------------------------------
// class VariableImplementation
//--------------------------------------------------------------------------

VariableImpl::VariableImpl (Variable *var, SearchTree *searchTree, size_t n, int priority)
: m_symbolicRep(var),
  m_searchTree(searchTree),
  m_indexDomain(searchTree->allocate(n)),
  m_size(n),
  m_priority(priority)
{
	m_searchTree->add(this);
}

VariableImpl::~VariableImpl()
{
}
